use crate::Vec2f;
use crate::Vec3f;

pub struct Triangle {
    pub positions: [Vec3f; 3],
    pub payload: PayLoad,
    // pub frag_shader: FragShader,
    // pub vert_shader: VertexShader,
}
pub struct PayLoad {
    pub tex_coords: Option<[Vec2f; 3]>,
    pub normals: Option<[Vec3f; 3]>,
    pub colors: Option<[Vec3f; 3]>,
}
impl Triangle {
    pub fn barycenter_for(&self, p: Vec2f) -> [f32; 3] {
        let [p0, p1, p2] = self.positions.map(|p| p.truncate());
        let (v0, v1, v2) = (p0 - p, p1 - p, p2 - p);
        let surface = (p1 - p0).perp_dot(p2 - p0);
        [v1.perp_dot(v2), v2.perp_dot(v0), v0.perp_dot(v1)].map(|v| v / surface)
    }
    pub fn contains(&self, p: Vec2f) -> bool {
        let p = Vec3f::from([p[0], p[1], 1.]);
        let [v0, v1, v2] = self.positions.map(|v| Vec3f::from([v[0], v[1], 1.]));
        let f0 = v1.cross(v0);
        let f1 = v2.cross(v1);
        let f2 = v0.cross(v2);
        if (p.dot(f0) * f0.dot(v2) > 0.)
            && (p.dot(f1) * f1.dot(v0) > 0.)
            && (p.dot(f2) * f2.dot(v1) > 0.)
        {
            // println!("contained in triangle");
            return true;
        } else {
            return false;
        }
    }
    // pub fn contains(&self, p: Vec2f) -> bool {
    //     let [p0, p1, p2] = self.positions.map(|p| p.truncate());
    //     let sig0 = !(p1 - p0).perp_dot(p - p0).is_sign_negative();
    //     let sig1 = !(p2 - p1).perp_dot(p - p1).is_sign_negative();
    //     let sig2 = !(p0 - p2).perp_dot(p - p2).is_sign_negative();
    //     sig0 == sig1 && sig1 == sig2
    // }
    pub fn new(positions: [Vec3f; 3], colors: [Vec3f; 3]) -> Self {
        Self {
            positions,
            payload: PayLoad {
                tex_coords: None,
                normals: None,
                colors: Some(colors),
            },
            // frag_shader,
        }
    }
}
